# common.py
"""公用模块"""

import os
from pathlib import Path
import sys
import time

import requests
from exceptions import NetworkError, BaiduApiError

"""常量定义，包含所有共享的常量"""
# ==================== 文件路径常量 ====================
# 用户主目录
USER_HOME = str(Path.home())

# 配置目录
CONFIG_DIR = os.path.join(USER_HOME, ".baidupan")
# 会话文件
SESSION_FILE = os.path.join(CONFIG_DIR, "session.json")
# 配置文件
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.ini")
# 认证文件
AUTH_FILE = os.path.join(CONFIG_DIR, "auth.json")
# 历史记录文件
HISTORY_FILE = os.path.join(CONFIG_DIR, "history")

# ==================== 会话常量 ====================
# 会话过期天数
SESSION_EXPIRY_DAYS = 7

# ==================== 命令列表常量 ====================
COMMAND_LIST = [
    'auth', 'config', 'refresh', 'logout', 'ls', 'cd', 'pwd', 'get', 'put',
    'lls', 'lcd', 'lpwd', 'lmkdir', 'mkdir', 'rm', 'mv', 'cp', 'tree', 'meta', 
    'rename', 'status', 'perf', 'quota', 'userinfo', 'help', 'debug', 'quit'
]

# ==================== 默认值常量 ====================
# 默认远程工作目录
DEFAULT_REMOTE_CWD = "/"
# 默认重定向URI
DEFAULT_REDIRECT_URI = "oob"
# 默认调试模式
DEFAULT_DEBUG_MODE = False

# ==================== 进度条常量 ====================
# 进度条最小更新间隔(秒)
PROGRESS_MIN_INTERVAL = 0.1
# 进度条长度
PROGRESS_BAR_LENGTH = 30

# ==================== 文件大小单位常量 ====================
SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']

# ==================== 时间格式常量 ====================
TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
TIME_FORMAT_SHORT = "%b %d, %Y %H:%M"

# ==================== 百度网盘API常量 ====================
# API基础URL
BAIDU_API_BASE_URL = "https://pan.baidu.com/rest/2.0/xpan"
# 认证URL
BAIDU_AUTH_URL = "https://openapi.baidu.com/oauth/2.0/authorize"
# Token URL
BAIDU_TOKEN_URL = "https://openapi.baidu.com/oauth/2.0/token"

# ==================== 错误消息常量 ====================
ERROR_MESSAGES = {
    "no_auth": "❌❌ 请先运行 'auth' 命令进行认证",
    "no_config": "❌❌ 未检测到客户端配置",
    "invalid_command": "❌❌ 未知命令: {}",
    "file_not_found": "❌❌ 文件不存在: {}",
    "dir_not_found": "❌❌ 目录不存在: {}",
    "network_error": "❌❌ 网络错误: {}",
    "api_error": "❌❌ API错误: {}",
}

# ==================== 成功消息常量 ====================
SUCCESS_MESSAGES = {
    "auth_success": "✅ 认证成功",
    "config_saved": "✅ 配置已保存",
    "download_complete": "✅ 下载完成: {}",
    "upload_complete": "✅ 上传完成: {}",
    "delete_success": "✅ 删除成功: {}",
    "mkdir_success": "✅ 目录创建成功: {}",
}

# ==================== 提示消息常量 ====================
INFO_MESSAGES = {
    "welcome": "🌐🌐 百度网盘SFTP命令行工具 - 输入 'help' 获取帮助",
    "current_remote_dir": "📁📁 远程当前目录: {}",
    "current_local_dir": "📁📁 本地当前目录: {}",
    "session_restored": "✅ 会话状态已恢复",
    "session_saved": "✅ 会话状态已保存",
}

# ==================== 符号常量 ====================
SYMBOLS = {
    "folder": "📂📂",
    "file": "📄📄",
    "image": "🖼🖼🖼️ ",
    "video": "🎬🎬",
    "audio": "🎵🎵",
    "pdf": "📕📕",
    "document": "📝📝",
    "spreadsheet": "📊📊",
    "archive": "📦📦",
    "success": "✅",
    "error": "❌❌",
    "warning": "⚠️ ",
    "download": "⬇⬇⬇⬇️ ",
    "upload": "⬆⬆⬆⬆️ ",
}

# 补全相关常量
COMPLETION_CONFIG = {
    'command_delimiters': ' \t\n',
    'max_completion_items': 100,
    'completion_ignore_case': True,
}


# 命令选项常量
COMMAND_OPTIONS = {
    'ls': ['-s', '-r', '-h'],
    'lls': ['-s', '-r', '-h'],
    'config': ['show', 'set'],
    'debug': ['on', 'off'],
    'logout': ['--all'],
}

# ==================== 排序选项常量 ====================
SORT_OPTIONS = {
    "name": "文件名",
    "time": "修改时间",
    "size": "文件大小"
}

# ==================== 排序方向常量 ====================
SORT_DIRECTIONS = {
    "asc": "正序",
    "desc": "倒序"
}

# ==================== 文件类型常量 ====================
FILE_TYPES = {
    "image": ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'],
    "video": ['.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv'],
    "audio": ['.mp3', '.wav', '.flac', '.aac', '.ogg', '.m4a'],
    "document": ['.doc', '.docx', '.txt', '.rtf'],
    "spreadsheet": ['.xls', '.xlsx', '.csv'],
    "presentation": ['.ppt', '.pptx'],
    "pdf": ['.pdf'],
    "archive": ['.zip', '.rar', '.7z', '.tar', '.gz'],
    "code": ['.py', '.js', '.java', '.c', '.cpp', '.html', '.css', '.php']
}

# ==================== 百度网盘错误码常量 ====================
BAIDU_ERROR_CODES = {
    31034: "文件或目录名错误",
    31039: "文件不存在",
    31066: "文件已存在",
    31077: "文件名含有非法字符",
    31078: "文件数量超出限制",
    31090: "容量不足",
    31113: "权限不足",
    31200: "参数错误",
    31201: "访问令牌无效",
    31202: "访问令牌过期",
    31203: "刷新令牌无效",
    31204: "应用信息错误",
    31205: "请求过于频繁",
    31206: "网络错误",
    31207: "服务器错误",
    31208: "操作超时",
    31209: "文件正在处理中",
    31210: "文件处理失败"
}

# ==================== 帮助命令常量 ====================
HELP_COMMANDS = {
    "auth": "进行认证获取访问令牌",
    "config": "显示或设置当前配置",
    "refresh": "刷新访问令牌",
    "logout": "清除认证信息",
    "ls": "列出远程目录内容",
    "cd": "更改远程当前工作目录",
    "pwd": "显示远程当前工作目录",
    "get": "下载远程文件到本地",
    "put": "上传本地文件到远程",
    "lls": "列出本地目录内容",
    "lcd": "更改本地当前工作目录",
    "lpwd": "显示本地当前工作目录",
    "lmkdir": "在本地创建文件夹",
    "mkdir": "创建远程目录",
    "rm": "删除远程文件或目录",
    "mv": "移动/重命名远程文件",
    "cp": "复制远程文件",
    "tree": "以树状结构显示目录内容",
    "meta": "获取文件元数据信息",
    "rename": "重命名文件/目录",
    "status": "显示当前工具状态",
    "quota": "查看网盘容量信息",
    "userinfo": "获取用户信息",
    "debug": "显示设置调试开关",
    "help": "显示帮助信息",
    "quit": "退出程序"
}

def format_size(size, is_dir=False):
    """
    格式化文件大小，目录固定显示为0
    
    参数:
        size: 文件大小（字节）
        is_dir: 是否为目录
    
    返回:
        格式化后的字符串
    """
    if is_dir:
        return "d".ljust(12)  # 目录显示为'd'，左对齐占12字符
    
    # 文件大小格式化
    units = ['B', 'KB', 'MB', 'GB', 'TB']
    unit_index = 0
    size_float = float(size)
    
    while size_float >= 1024 and unit_index < len(units) - 1:
        size_float /= 1024
        unit_index += 1
    
    # 根据大小选择合适的精度
    if unit_index == 0:  # 字节
        size_str = f"{size_float:.0f} {units[unit_index]}"
    elif size_float < 10:  # 小于10，保留1位小数
        size_str = f"{size_float:.1f} {units[unit_index]}"
    else:  # 大于10，保留整数
        size_str = f"{size_float:.0f} {units[unit_index]}"
    
    return size_str.rjust(12)  # 右对齐占12字符


def format_timestamp(timestamp):
    """
    格式化时间戳为 '月 日, 年 时:分' 格式
    
    参数:
        timestamp: 时间戳
    
    返回:
        格式化后的时间字符串
    """
    if not timestamp:
        return "未知时间".ljust(20)
    
    try:
        from datetime import datetime
        # 将时间戳转换为datetime对象
        dt = datetime.fromtimestamp(timestamp)
        # 格式化为 "月 日, 年 时:分"
        return dt.strftime("%b %d, %Y %H:%M").ljust(20)
    except:
        return "无效时间".ljust(20)

def format_percent(percent):
    """格式化百分比"""
    return f"{percent:.1f}%"

def format_speed(speed):
    """格式化速度"""
    for unit in SIZE_UNITS:
        if speed < 1024.0:
            return f"{speed:.1f} {unit}/s"
        speed /= 1024.0
    return f"{speed:.1f} PB/s"

def ensure_config_dir():
    """确保配置目录存在"""
    if not os.path.exists(CONFIG_DIR):
        os.makedirs(CONFIG_DIR, exist_ok=True)
    return CONFIG_DIR

def handle_error(error_type, *args):
    """处理错误消息"""
    message = ERROR_MESSAGES.get(error_type, "未知错误")
    if args:
        return message.format(*args)
    return message

def handle_success(success_type, *args):
    """处理成功消息"""
    message = SUCCESS_MESSAGES.get(success_type, "操作成功")
    if args:
        return message.format(*args)
    return message

def handle_info(info_type, *args):
    """处理信息消息"""
    message = INFO_MESSAGES.get(info_type, "")
    if args:
        return message.format(*args)
    return message

import logging

def setup_logging():
    """设置日志记录"""
    log_dir = Path.home() / ".baidupan" / "logs"
    if not log_dir.exists():
        log_dir.mkdir(parents=True, exist_ok=True)
    
    log_file = log_dir / "baidupan.log"
    
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        handlers=[
            # logging.StreamHandler(sys.stdout),
            logging.FileHandler(log_file)
        ]
    )
    
    return logging.getLogger(__name__)

def with_retry(max_retries=3, retry_delay=1, backoff_factor=2):
    """重试装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            retry_codes = [6, 111, 133, 31341, 42905, 31034]
            retries = 0
            while retries <= max_retries:
                try:
                    return func(*args, **kwargs)
                except (BaiduApiError, NetworkError, requests.RequestException) as e:
                    retries += 1
                   # 检查是否达到最大重试次数
                    if retries > max_retries:
                        print(f"❌ 操作失败，已达到最大重试次数 ({max_retries})")
                        raise
                    
                    # 计算延迟时间（指数退避）
                    delay = retry_delay * (backoff_factor ** (retries - 1))

                    # 特殊错误码处理
                    if isinstance(e, BaiduApiError):
                        # 可重试代码集中的才会重试
                        if e.errno not in retry_codes:
                            raise

                        # 特定错误码处理
                        errno = e.errno
                        if errno == 31034:  # 频控错误
                            delay = max(delay, 5)  # 延长等待时间

                    # 对于网络错误，显示更友好的信息
                    if isinstance(e, (NetworkError, requests.RequestException)):
                        print(f"🌐 网络连接问题，请检查网络后重试")

                    # 打印错误信息和重试提示
                    error_type = type(e).__name__
                    print(f"⚠️  操作失败 ({retries}/{max_retries}): {error_type}: {e}")
                    print(f"🔄 将在 {delay:.1f} 秒后自动重试...")

                    time.sleep(delay)
        return wrapper
    return decorator
